package com.example.demo3.controller;


import com.example.demo3.config.AjaxResult;
import com.example.demo3.date.ModelImportForm;
import com.example.demo3.date.StrategyRunForm;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 流程测试
 */
@Api(value = "流程测试")
@Slf4j
@RestController
@RequestMapping("/flow/monitor")
public class WorkflowTestController {

    @Resource
    private ProcessEngine processEngine;
    @Resource
    private HistoryService historyService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ProcessEngineConfiguration processEngineConfiguration;

    //部署一个流程
    @Operation(summary = "部署一个流程")
    @PostMapping("/deployProcess")
    public AjaxResult deployProcess() {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/diagram (14).bpmn")
                .deploy();
        System.out.println("流程部署ID：" + deployment.getId());
        return AjaxResult.success();
    }

    //查询部署的流程
    @Operation(summary = "查询部署的流程")
    @PostMapping("/queryDeploy")
    public AjaxResult queryDeploy() {
        String processDefinitionKey = "newProcessKey";
        ProcessDefinition processDefinition = processEngine.getRepositoryService()
                .createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .singleResult();

        System.out.println("流程定义信息：" + processDefinition.getName());
        return AjaxResult.success();
    }

    //启动一个流程实例
    @Operation(summary = "启动一个流程实例")
    @PostMapping("/startProcessInstance")
    public AjaxResult startProcessInstance() throws FileNotFoundException {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //定义流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("day", 5);

//        StrategyRunForm strategyRunForm = new StrategyRunForm();
//        strategyRunForm.setStrategyId(1234l);
//        ModelImportForm modelImportForm = new ModelImportForm();
//        modelImportForm.setBody("{\"body\":\"习明泽\"}");
//        strategyRunForm.setModelImportForm(modelImportForm);
//        strategyRunForm.setB(new byte[1000]);
//        variables.put("strategyRunForm", strategyRunForm);
//        variables.put("skip", true);
//        variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);

        String processDefinitionKey = "askleave";
        processDefinitionKey = "fenzhitest";
        processDefinitionKey = "parallel";
        processDefinitionKey = "Process_1722322617886";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables); //这个key是xml文件里面process元素的id属性
        //runtimeService.startProcessInstanceById() //根据ID来启动，这个ID是数据库表里面的ID
        //8c247508-1bfd-11ef-b157-1e4d08627f39
        System.out.println("流程实例：" + processInstance.getId());
        return AjaxResult.success();
    }

    //获取某个候选组的任务列表
    @Operation(summary = "获取某个候选组的任务列表")
    @PostMapping("/getTaskListByGroup")
    public AjaxResult getTaskListByGroup() {
        TaskService taskService = processEngine.getTaskService();
        //根据候选组来查询任务
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("ceo").list();
        System.out.println("你有" + tasks.size() + "个任务");
        for (Task task : tasks) {
            System.out.println("任务名称：" + task.getName() + ",任务ID：" + task.getId());
        }
        return AjaxResult.success();
    }

    //获取某个用户的任务列表
    @Operation(summary = "获取某个用户的任务列表")
    @PostMapping("/getTaskListByUser")
    public AjaxResult getTaskListByUser() {
        TaskService taskService = processEngine.getTaskService();
        //根据候选组来查询任务
        List<Task> tasks = taskService.createTaskQuery().taskAssignee("lisi").list();
        System.out.println("你有" + tasks.size() + "个任务");
        for (Task task : tasks) {
            System.out.println("任务名称：" + task.getName() + ",任务ID：" + task.getId());
        }
        return AjaxResult.success();
    }

    //获取任务的变量信息
    @Operation(summary = "获取任务的变量信息")
    @PostMapping("/getTaskVariables")
    public AjaxResult getTaskVariables() {
        TaskService taskService = processEngine.getTaskService();
        //获取某一个任务
        Task task = taskService.createTaskQuery().taskId("9dcd7bcd-2fda-11ef-bfd9-52eb715eb8fc").singleResult();
        //获取任务的变量信息
        Map<String, Object> variables = taskService.getVariables(task.getId());
        System.out.println("变量信息：" + variables.toString());
        return AjaxResult.success();
    }

    //完成一个任务
    @Operation(summary = "完成一个任务")
    @PostMapping("/taskFinish")
    public AjaxResult taskFinish() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", true);

        String taskId = "50969146-2fdc-11ef-9b55-52eb715eb8fc";
        TaskService taskService = processEngine.getTaskService();
        taskService.complete(taskId, variables);
        return AjaxResult.success();
    }

    //查询历史记录
    @Operation(summary = "查询历史记录")
    @PostMapping("/getHistory")
    public AjaxResult getHistory() {
        HistoryService historyService = processEngine.getHistoryService();

        String processInstanceId = "519c8945-3db6-11ef-a9e8-52eb715eb8fc";

        List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished() //要已完成的
                .orderByHistoricActivityInstanceEndTime().asc().list();

        for (HistoricActivityInstance activity : activities) {
            System.out.println("活动名称：" + activity.getActivityName() + " 花费了" + activity.getDurationInMillis() + "毫秒");
        }
        return AjaxResult.success();
    }

    @Operation(summary = "流程图进度追踪")
    @RequestMapping(value = {"/traceProcess"}, method = RequestMethod.GET)
    public void traceprocess(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
        this.generateFlowChart(processInstanceId, response.getOutputStream());
    }

    public void generateFlowChart(String processInstanceId, OutputStream outputStream) {
        if (StringUtils.isEmpty(processInstanceId)) {
            log.error("processInstanceId is null");
            return;
        }
        // 获取历史流程实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
                .singleResult();
        // 获取流程中已经执行的节点
        String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
        List<String> highLightedActivities = new ArrayList<>();
        // 获得活动的节点
        List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> highLightedFlows = new ArrayList<>();
        for (HistoricActivityInstance tempActivity : highLightedActivityList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivities.add(activityId);
            if ("sequenceFlow".equals(tempActivity.getActivityType())) {
                highLightedFlows.add(tempActivity.getActivityId());
            }
        }
        // 获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engConf = processEngineConfiguration.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, highLightedFlows, "宋体",
                "宋体", "宋体", engConf.getClassLoader(), 1.0, true);
        byte[] buf = new byte[1024];
        int length;
        try {
            while ((length = in.read(buf)) != -1) {
                outputStream.write(buf, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.closeSilently(outputStream);
            IoUtil.closeSilently(in);
        }
    }


    @Operation(summary = "复制一个流程")
    @PostMapping("/copyProcess")
    public AjaxResult copyProcess(String processDefinitionId) {
        // 获取原始流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        // 修改流程定义的名称和key
        String newProcessDefinitionKey = "newProcessKey"; // 确保这个key是唯一的
        String newProcessDefinitionName = "New Process Name";

        Process mainProcess = bpmnModel.getMainProcess();
        mainProcess.setId(newProcessDefinitionKey);
        mainProcess.setName(newProcessDefinitionName);

        // 部署新流程定义
        Deployment deployment = repositoryService.createDeployment()
                .name(newProcessDefinitionName)
                .key(newProcessDefinitionKey)
                .addBpmnModel(processDefinition.getResourceName(), bpmnModel)
                .deploy();


        System.out.println("New process deployed with id: " + deployment.getId());
        return AjaxResult.success();
    }



}
